﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace BinaryClockScreensaverCore
{
    public partial class BinaryClock : UserControl
    {
        Dictionary<int, Point> points;
        BinaryTime activePoints;
        Size binaryClockSize;
        Size nodeSize;

        Image imageHour;
        Image imageMinute;
        Image imageSecond;

        int curHour;
        int curMinute;
        int curSecond;

        enum BinaryTime : int
        {
            HourTens2 = 0x00000004,
            HourTens1 = 0x00000008,
            HourOnes8 = 0x00000010,
            HourOnes4 = 0x00000020,
            HourOnes2 = 0x00000040,
            HourOnes1 = 0x00000080,
            MinuteTens4 = 0x00000200,
            MinuteTens2 = 0x00000400,
            MinuteTens1 = 0x00000800,
            MinuteOnes8 = 0x00001000,
            MinuteOnes4 = 0x00002000,
            MinuteOnes2 = 0x00004000,
            MinuteOnes1 = 0x00008000,
            SecondTens4 = 0x00020000,
            SecondTens2 = 0x00040000,
            SecondTens1 = 0x00080000,
            SecondOnes8 = 0x00100000,
            SecondOnes4 = 0x00200000,
            SecondOnes2 = 0x00400000,
            SecondOnes1 = 0x00800000
        }

        [DefaultValue(null)]
        public Image ImageHour
        {
            get { return imageHour; }
            set { imageHour = value; base.Invalidate(); }
        }

        [DefaultValue(null)]
        public Image ImageMinute
        {
            get { return imageMinute; }
            set { imageMinute = value; base.Invalidate(); }
        }

        [DefaultValue(null)]
        public Image ImageSecond
        {
            get { return imageSecond; }
            set { imageSecond = value; base.Invalidate(); }
        }

        [DefaultValue(typeof(Size), "36, 36")]
        public Size NodeSize
        {
            get
            {
                return nodeSize;
            }
            set
            {
                nodeSize = value;
                binaryClockSize = new Size(((nodeSize.Width + 10) * 7), (nodeSize.Height + 10) * 5);
                base.Invalidate();
                CalculatePosition(new Point(0, 0));
            }
        }

        public BinaryClock()
        {
            points = new Dictionary<int, Point>();
            NodeSize = new Size(36, 36);

            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
                activePoints = (BinaryTime)0x00FFFFFF;
            else
                activePoints = 0;

            InitializeComponent();

            CalculatePosition(new Point(0, 0));
        }

        public void Start()
        {
            //CalculatePosition();
            timer1.Start();
            timer2.Start();
        }

        public void Stop()
        {
            timer1.Stop();
            timer2.Stop();
        }

        void CalculatePosition()
        {
            if (this.Width < (binaryClockSize.Width + 20) || this.Height < (binaryClockSize.Height + 20))
                return;

            CalculatePosition(new Point(RandomNumbers.Next(10, this.Size.Width - binaryClockSize.Width), RandomNumbers.Next(10, this.Size.Height - binaryClockSize.Height)));
        }

        void CalculatePosition(Point point)
        {
            int counter = 0;
            int c = 0;
            int r = 0;
            int j = 0;

            points.Clear();

            for (int i = 1; i <= 0x00800000; i <<= 1)
            {
                points.Add(i, new Point(point.X + (NodeSize.Width + 10) * c + 10 * r, point.Y + (NodeSize.Height + 10) * j));

                counter++;

                j++;
                if (j > 3)
                    j = 0;

                if (counter % 4 == 0)
                    c++;

                if (counter % 8 == 0)
                    r++;
            }

            base.Invalidate();
        }

        private void DrawBinaryTime(int hours, int minutes, int seconds)
        {
            if (curHour == hours && curMinute == minutes && curSecond == seconds)
                return;

            activePoints = 0;

            //Hours
            if (hours >= 20)
            {
                activePoints |= BinaryTime.HourTens2;
                hours %= 20;
            }
            if (hours >= 10)
            {
                activePoints |= BinaryTime.HourTens1;
                hours %= 10;
            }
            if (hours >= 8)
            {
                activePoints |= BinaryTime.HourOnes8;
                hours %= 8;
            }
            if (hours >= 4)
            {
                activePoints |= BinaryTime.HourOnes4;
                hours %= 4;
            }
            if (hours >= 2)
            {
                activePoints |= BinaryTime.HourOnes2;
                hours %= 2;
            }
            if (hours >= 1)
            {
                activePoints |= BinaryTime.HourOnes1;
                hours %= 1;
            }


            //Minutes
            if (minutes >= 40)
            {
                activePoints |= BinaryTime.MinuteTens4;
                minutes %= 40;
            }
            if (minutes >= 20)
            {
                activePoints |= BinaryTime.MinuteTens2;
                minutes %= 20;
            }
            if (minutes >= 10)
            {
                activePoints |= BinaryTime.MinuteTens1;
                minutes %= 10;
            }
            if (minutes >= 8)
            {
                activePoints |= BinaryTime.MinuteOnes8;
                minutes %= 8;
            }
            if (minutes >= 4)
            {
                activePoints |= BinaryTime.MinuteOnes4;
                minutes %= 4;
            }
            if (minutes >= 2)
            {
                activePoints |= BinaryTime.MinuteOnes2;
                minutes %= 2;
            }
            if (minutes >= 1)
            {
                activePoints |= BinaryTime.MinuteOnes1;
                minutes %= 1;
            }


            //Seconds
            if (seconds >= 40)
            {
                activePoints |= BinaryTime.SecondTens4;
                seconds %= 40;
            }
            if (seconds >= 20)
            {
                activePoints |= BinaryTime.SecondTens2;
                seconds %= 20;
            }
            if (seconds >= 10)
            {
                activePoints |= BinaryTime.SecondTens1;
                seconds %= 10;
            }
            if (seconds >= 8)
            {
                activePoints |= BinaryTime.SecondOnes8;
                seconds %= 8;
            }
            if (seconds >= 4)
            {
                activePoints |= BinaryTime.SecondOnes4;
                seconds %= 4;
            }
            if (seconds >= 2)
            {
                activePoints |= BinaryTime.SecondOnes2;
                seconds %= 2;
            }
            if (seconds >= 1)
            {
                activePoints |= BinaryTime.SecondOnes1;
                seconds %= 1;
            }

            base.Invalidate();
        }


        private void BinaryClock_Paint(object sender, PaintEventArgs e)
        {
            if (ImageHour == null || ImageMinute == null || ImageSecond == null)
                return;

            e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;

            //hours
            for (int i = 0x0001; i <= 0x00000080; i <<= 1)
            {
                if (((int)activePoints & i) == i)
                    e.Graphics.DrawImage(ImageHour, points[i].X, points[i].Y, NodeSize.Width, NodeSize.Height);
            }

            //minutes
            for (int i = 0x0100; i <= 0x0008000; i <<= 1)
            {
                if (((int)activePoints & i) == i)
                    e.Graphics.DrawImage(ImageMinute, points[i].X, points[i].Y, NodeSize.Width, NodeSize.Height);
            }

            //seconds
            for (int i = 0x00010000; i <= 0x00800000; i <<= 1)
            {
                if (((int)activePoints & i) == i)
                    e.Graphics.DrawImage(ImageSecond, points[i].X, points[i].Y, NodeSize.Width, NodeSize.Height);
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            DrawBinaryTime(DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second);

            curHour = DateTime.Now.Hour;
            curMinute = DateTime.Now.Minute;
            curSecond = DateTime.Now.Second;
        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            CalculatePosition();
        }

        private void BinaryClock_SizeChanged(object sender, EventArgs e)
        {
            CalculatePosition();
        }
    }
}
